package pl.jtb.ctl.tabory.ui.re.ui.vr;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.SectionPart;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;

import pl.jtb.ctl.tabory.dao.api.services.ICompositionService;
import pl.jtb.ctl.tabory.dao.api.services.IVagonService;
import pl.jtb.ctl.tabory.dao.data.vo.CompositionVO;
import pl.jtb.ctl.tabory.dao.data.vo.VagonVO;
import pl.jtb.ctl.tabory.dao.impl.mybatis.servicemanager.ServiceManager;
import pl.jtb.ctl.tabory.ui.osgi.UiBundleActivator;
import pl.jtb.ctl.tabory.ui.re.beans.VagonBean;
import pl.jtb.ctl.tabory.ui.re.osgi.Activator;

public class VagonReportSection extends SectionPart {

    public final static String ID = "pl.jtb.ctl.tabory.ui.re.ui.vr.VagonReportEditor";
    private final Logger log = Logger.getLogger(VagonReportEditor.class);

    private final static String EXPORT_FOLDER = Platform.getInstanceLocation().getURL().getPath();
    private org.eclipse.swt.widgets.List reportListComposite;
    private Browser reportBrowser;
    private Button buttonCreateReport;

    private List<String> listFileNames = new ArrayList<String>();

    public VagonReportSection(Composite parent, FormToolkit toolkit, int style) {
        super(parent, toolkit, style);
        initGui(toolkit);
        postInitGui();
    }

    private void initGui(FormToolkit toolkit) {
        getSection().setText(Activator.getMessage("report.title"));
        Composite container = toolkit.createComposite(getSection());
        GridLayoutFactory.fillDefaults().numColumns(2).applyTo(container);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(container);
        getSection().setClient(container);
        container.setLayout(new GridLayout(2, false));

        Form formReportsList = toolkit.createForm(container);
        formReportsList.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true, 1, 1));
        toolkit.paintBordersFor(formReportsList);
        formReportsList.getBody().setLayout(new GridLayout(1, false));

        buttonCreateReport = toolkit.createButton(formReportsList.getBody(), Activator.getMessage("report.vagon.labels.create"), SWT.NONE);
        buttonCreateReport.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));

        reportListComposite = new org.eclipse.swt.widgets.List(formReportsList.getBody(), SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        GridData gd_reportListComposite = new GridData(SWT.FILL, SWT.FILL, false, true, 1, 1);
        gd_reportListComposite.widthHint = 200;
        reportListComposite.setLayoutData(gd_reportListComposite);
        toolkit.adapt(reportListComposite, true, true);

        Menu popupMenu = new Menu(reportListComposite);
        MenuItem copyToClipboarItem = new MenuItem(popupMenu, SWT.NONE);
        copyToClipboarItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                new CopyFileToClipboar().run();
            }
        });
        copyToClipboarItem.setText(Activator.getMessage("report.listreports.popupmenu.copy"));
        reportListComposite.setMenu(popupMenu);

        Form formReportViewer = toolkit.createForm(container);
        formReportViewer.setTouchEnabled(true);
        formReportViewer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        toolkit.paintBordersFor(formReportViewer);
        formReportViewer.getBody().setLayout(new GridLayout(1, false));

        reportBrowser = new Browser(formReportViewer.getBody(), SWT.BORDER);
        reportBrowser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        toolkit.adapt(reportBrowser);
        toolkit.paintBordersFor(reportBrowser);
    }

    private void postInitGui() {
        fillListFiles();
        reportListComposite.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseDoubleClick(MouseEvent e) {
                org.eclipse.swt.widgets.List source = (org.eclipse.swt.widgets.List) e.getSource();
                String[] selection = source.getSelection();
                String selectedFile = selection[0];
                performOpenReport(selectedFile);
            }
        });
        buttonCreateReport.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                try {
                    performCreateReport();
                } catch (InvocationTargetException e) {
                    log.error(e.getMessage(), e);
                    MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                    MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
                }
            }
        });
    }

    private void performCreateReport() throws InvocationTargetException, InterruptedException {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
        StringBuilder builder = new StringBuilder(Activator.getMessage("report.vagon.newreport.defaultname"));
        builder.append("_");
        builder.append(dateFormat.format(new Date()));

        InputDialog stationNameInputDialog = new InputDialog(getSection().getShell(), Activator.getMessage("report.vagon.create.title"), Activator.getMessage("report.vagon.create.message"), builder.toString(), null);
        if (Window.OK == stationNameInputDialog.open()) {
            final String reportName = stationNameInputDialog.getValue();
            if (reportName.isEmpty()) {
                return;
            }
            if (reportName.contains(".")) {
                MessageDialog.openError(getSection().getShell(), Activator.getMessage("report.vagon.create.wrongname.title"), Activator.getMessage("report.vagon.create.wrongname.message"));
                return;
            }
            PlatformUI.getWorkbench().getProgressService().run(false, true, new IRunnableWithProgress() {
                @Override
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    try {
                        monitor.beginTask(Activator.getMessage("report.common.doing"), 5);
                        String exportPath = EXPORT_FOLDER + "/" + reportName + ".pdf";
                        monitor.worked(1);
                        InputStream reportStream = this.getClass().getResourceAsStream("/resources/vagonReport.jasper");
                        monitor.worked(2);
                        Map<String, Object> parametersMap = new HashMap<String, Object>();
                        JasperPrint jasperPrint = JasperFillManager.fillReport(reportStream, parametersMap, new JRBeanCollectionDataSource(getVagonBeans()));
                        monitor.worked(3);
                        JasperExportManager.exportReportToPdfFile(jasperPrint, exportPath);
                        monitor.worked(4);
                        fillListFiles();
                        monitor.worked(5);
                        String reportFileName = reportName + ".pdf";
                        performOpenReport(reportFileName);
                        reportListComposite.setSelection(listFileNames.indexOf(reportFileName));
                        monitor.done();
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
                    }
                }
            });
        }
    }

    private void fillListFiles() {
        reportListComposite.removeAll();
        File workspaceFolder = new File(EXPORT_FOLDER);
        File[] listFiles = workspaceFolder.listFiles();
        listFileNames.clear();
        if (listFiles != null) {
            for (File file : listFiles) {
                if (file.getName().endsWith(".pdf")) {
                    reportListComposite.add(file.getName());
                    listFileNames.add(file.getName());
                }
            }
        }
    }

    private void performOpenReport(String selectedFile) {
        reportBrowser.setUrl(new File(EXPORT_FOLDER + "\\" + selectedFile).toString());
        reportBrowser.setFocus();
    }

    private List<VagonBean> getVagonBeans() throws IOException, Exception {
        ICompositionService compositionService = ServiceManager.getInstance().getCompositionService();
        IVagonService vagonService = ServiceManager.getInstance().getVagonService();
        List<CompositionVO> listAllCompositions = compositionService.getListAllCompositions();
        Map<CompositionVO, List<VagonVO>> mapRelation = new LinkedHashMap<CompositionVO, List<VagonVO>>();
        for (CompositionVO composition : listAllCompositions) {
            mapRelation.putAll(compositionService.getCompositionVagonRelation(composition));
        }
        List<VagonVO> listAllVagons = vagonService.getListAllVagons();
        List<VagonBean> listBeans = new ArrayList<VagonBean>();
        for (VagonVO vagonVO : listAllVagons) {
            VagonBean bean = new VagonBean();
            Double distance = vagonVO.getDistance();
            if (distance == null) {
                distance = 0D;
            }
            Double revisionCorrection = vagonVO.getRevisionCorrection();
            if (revisionCorrection == null) {
                revisionCorrection = 0D;
            }
            Double revisionDistance = vagonVO.getRevisionDistance();
            if (revisionDistance == null) {
                revisionDistance = 0D;
            }
            CompositionVO compositionForVagon = getCompositionForVagon(mapRelation, vagonVO);
            bean.setCompositionName(compositionForVagon == null ? "---" : compositionForVagon.getInternalId());
            bean.setDistance(distance);
            bean.setDistanceCorrected(distance - revisionCorrection);
            bean.setDistanceCorrection(revisionCorrection);
            bean.setRevOneFrom(vagonVO.getRevOneFrom());
            bean.setRevOneUntil(vagonVO.getRevOneUntil());
            bean.setRevTwoFrom(vagonVO.getRevTwoFrom());
            bean.setRevTwoUntil(vagonVO.getRevTwoUntil());
            bean.setVagonName(vagonVO.getInternalId());
            listBeans.add(bean);
        }
        return listBeans;
    }

    private CompositionVO getCompositionForVagon(Map<CompositionVO, List<VagonVO>> mapVagonComposition, final VagonVO vagon) {
        for (Entry<CompositionVO, List<VagonVO>> entry : mapVagonComposition.entrySet()) {
            if (entry.getValue().contains(vagon)) {
                return entry.getKey();
            }
        }
        return null;
    }

    @SuppressWarnings("unused")
    private Map<String, Object> getReportParameters() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("headerVagonName", Activator.getMessage("report.vagon.jasperparam.header.vagonname"));
        map.put("headerCompositionName", Activator.getMessage("report.vagon.jasperparam.header.compositionname"));
        map.put("headerDistance", Activator.getMessage("report.vagon.jasperparam.header.distance"));
        map.put("headerDistanceCorrection", Activator.getMessage("report.vagon.jasperparam.header.distancecorrection"));
        map.put("headerDistanceCorrected", Activator.getMessage("report.vagon.jasperparam.header.distancecorrected"));
        map.put("headerRevOneFrom", Activator.getMessage("report.vagon.jasperparam.header.revonefrom"));
        map.put("headerRevOneUntil", Activator.getMessage("report.vagon.jasperparam.header.revoneuntil"));
        map.put("headerRevTwoFrom", Activator.getMessage("report.vagon.jasperparam.header.revtwofrom"));
        map.put("headerRevTwoUntil", Activator.getMessage("report.vagon.jasperparam.header.revtwountil"));
        return map;
    }

    private class CopyFileToClipboar extends Thread {
        @Override
        public void run() {
            Display display = Display.getCurrent();
            Clipboard clipboard = new Clipboard(display);
            String[] selection = reportListComposite.getSelection();
            String fileName = selection[0];
            if (fileName == null || fileName.isEmpty()) {
                return;
            }
            fileName = EXPORT_FOLDER + fileName;
            fileName = fileName.substring(1, fileName.length());
            String[] data = { fileName };
            clipboard.setContents(new Object[] { data }, new Transfer[] { FileTransfer.getInstance() });
            clipboard.dispose();
        }
    }
}
